package cn.tedu.weibo.exception;

import cn.tedu.weibo.result.JSonResult;
import cn.tedu.weibo.result.Status;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.*;

import javax.validation.ConstraintViolationException;

/**
 * 全局异常处理器
 * 使用全局异常处理来对SpringMVC框架中所有Controller抛出的异常统一在这里处理
 * 全局异常处理由SpringMVC框架调度
 *
 * @ControllerAdvice注解 使用该注解标注的类被认定为全局异常处理器
 * 那么一旦一个Controller中的方法抛出异常时，框架会优先找到当前类来进行处理
 * @RestControllerAdvice注解与@RestController道理一样 使用它后，所有方法返回JSON格式时不用再单独添加@ResponseBody注解了
 * <p>
 * <p>
 * 处理异常的顺序:
 * 我们可以将当前类中处理各种异常的方法想象为原来使用try-catch中的catch。
 * 在这里方法在类中定义的顺序无所谓，不用像catch一样必须是子类型异常在上，超类型异常在下
 * 执行优先级:
 * 1:异常类型完全匹配最优先
 * 2:超类异常(可以覆盖实际抛出的异常)
 */


//相当于catch(RuntimeException e)
//@ControllerAdvice
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {
/*
    @ExceptionHandler   //加这个SpringMVC 才知道这个方法类似与一个catch
//    @ResponseBody
    //优先找同类型异常没有就找超类型异常 IllegalArgumentException继承RuntimeException
    public JSonResult doHandleRuntimeException(RuntimeException e){
        System.out.println("出现了RuntimeException");
        return new JSonResult(Status.UNKNOWN_ERROR);
    }
*/


    //相当于catch(IllegalArgumentException e)
//    @ExceptionHandler
////    @ResponseBody
//    public JSonResult doHandleIllegalArgumentException(IllegalArgumentException e) {
//        System.out.println("出现了参数不合法异常");
//        return new JSonResult(Status.OPERATION_FAILED, e.getMessage());
//    }

    /**
     * 通常捕获最大类型的异常(Exception或Throwable)是用来避免因系统出现异常无法处理
     * 的情况导致响应5000错误。
     */
    @ExceptionHandler
    public JSonResult doHandlerException(Exception e){
        log.error(e.getMessage(),e);
        return new JSonResult(Status.UNKNOWN_ERROR,e.getMessage());
    }
    @ExceptionHandler

    public JSonResult doHandleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        //Controller方法在验证用户提交数据时不通过会抛出上述异常
        /*
            本身的e.getMessage()在验证不通过时抛出的异常中内容繁多
            我们可以仅将原因回复，此时使用下面的操作
//         */
        String message = e.getFieldError().getDefaultMessage();
        log.warn(message,e);
        return new JSonResult(Status.VALIDATE_FAILED, message);

    }

    @ExceptionHandler
    public JSonResult doHandleConstraintViolationException(ConstraintViolationException e) {
        String message = e.getMessage();
        //"data": "findById.id: 微博ID只能在1-999之间"
        message = message.substring(message.indexOf(":") + 1).trim();
        //从id: 后面+1个位置开始截取再去掉空格
        /*
        message.indexOf(":")：找到冒号 : 的位置。
        substring(...)：从冒号后面开始截取子字符串，去掉前面的字段名（如 findById.id）。
        trim()：去除前后多余的空格。
         */
        log.warn(message,e);
        return new JSonResult(Status.VALIDATE_FAILED, message);
    }
}
